import { PlusOutlined } from "@ant-design/icons";
import { GetProp, Upload, UploadFile, UploadProps, Image, App } from "antd";
import { UploadListType } from "antd/es/upload/interface";
import { ReactNode, useState } from "react";

// 上传文件类型定义,可以根据需求添加类型，参考：https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
type UploadType =
  | "image/gif"
  | "image/jpeg"
  | "image/png"
  | "image/webp"
  | "image/bmp"
  | "image/x-icon";

interface IBmUploadProps {
  listType?: UploadListType;
  fileList: UploadFile[];
  limit?: number;
  customUploadContainer?: ReactNode;
  format?: UploadType[];
  accept?: string;
  onChange: (fileList: UploadFile[]) => void;
  onBeforeUpload?: (file: FileType) => void;
}

export type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];

// 二进制数据转base64
const getBase64 = (file: FileType): Promise<string> =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = (error) => reject(error);
  });

const uploadButton = (
  <button style={{ border: 0, background: "none" }} type="button">
    <PlusOutlined />
    <div style={{ marginTop: 8 }}>Upload</div>
  </button>
);
const BmUpload: React.FC<IBmUploadProps> = ({
  listType,
  fileList,
  limit = 1,
  customUploadContainer,
  format,
  accept = "image/*",
  onChange,
  onBeforeUpload,
}) => {
  const [previewOpen, setPreviewOpen] = useState(false);
  const [previewImage, setPreviewImage] = useState("");
  const [localFileList, setLocalFileList] = useState<UploadFile[]>([]);
  const { message } = App.useApp()
  const handlePreview = async (file: UploadFile) => {
    if (!file.url && !file.preview) {
      file.preview = await getBase64(file.originFileObj as FileType);
    }

    setPreviewImage(file.url || (file.preview as string));
    setPreviewOpen(true);
  };

  const handleChange: UploadProps["onChange"] = ({
    file: newFile,
    fileList: newFileList,
  }) => {
    const list = newFileList.map((file) => {
      if (file.response) {
        return {
          uid: file.uid,
          name: file.name,
          url: file.response.fileId,
        };
      } else {
        return {
          uid: file.uid,
          name: file.name,
          url: file.url,
        };
      }
    });
    // 图片上传结束
    if (newFile.status === "done") {
      // 文件格式 {uid, name, url}
      onChange([...fileList, ...list]);
    }
    setLocalFileList(list);
  };

  // 上传之前进行格式校验
  const handleBeforeUpload = (file: FileType) => {
    try {
      if (format) {
        if (!format.includes(file.type as UploadType)) {
          message.error(`${file.name} is not a ${format.join(" or ")} file`);
          return false;
        }
      }
      if (onBeforeUpload) {
        return onBeforeUpload(file);
      }
    } catch (err: unknown) {
      message.error((err as {message: string}).message);
    }

    return true;
  };

  const defaultListType = customUploadContainer ? "text" : "picture-card";

  return (
    <>
      <Upload
        action={import.meta.env.YFW_UPLOAD_URL}
        name="file"
        listType={listType || defaultListType}
        fileList={localFileList}
        maxCount={limit}
        data={{ diskId: 0 }}
        defaultFileList={fileList}
        showUploadList={!customUploadContainer}
        accept={accept}
        beforeUpload={handleBeforeUpload}
        onPreview={handlePreview}
        onChange={handleChange}
      >
        {customUploadContainer
          ? customUploadContainer
          : fileList.length >= limit
          ? null 
          : uploadButton}
      </Upload>
      {previewImage && (
        <Image
          wrapperStyle={{ display: "none" }}
          preview={{
            visible: previewOpen,
            onVisibleChange: (visible) => setPreviewOpen(visible),
            afterOpenChange: (visible) => !visible && setPreviewImage(""),
          }}
          src={previewImage}
        />
      )}
    </>
  );
};

export default BmUpload;
